// 小球碰撞脚本
const canvas = document.getElementById('myCanvas');
const cxt = canvas.getContext('2d');

function draw(cxt) {
    for (var i = 0; i < balls.length; i++) {
        cxt.fillStyle = balls[i].color;
        cxt.beginPath();
        cxt.arc(balls[i].x, context.canvas.height - balls[i].y, balls[i].r, 0, 2 * Math.PI);
        cxt.closePath();
        cxt.fill();
    }
}
function initballs() {
    balls = [];
    ballsnum = Math.random() * 60;
    width = 250;
    height = 20;
    speed = 0.5
    R = 3;
    for (var i = 0; i < ballsnum; i++) {
        balls[i] = {
            m: R * R * 0.01,
            x: Math.random() * width,
            y: Math.random() * height,
            vx: Math.random() * speed,
            vy: Math.random() * speed,
            ax: 0,
            ay: 0,
            r: R,
            color: 'rgb(' + Math.floor(Math.random() * 256) + ',' + Math.floor(Math.random() * 256) + ',' + Math.floor(Math.random() * 256) + ')'
        }
    }
}
function render(cxt) {
    cxt.clearRect(0, 0, cxt.canvas.width, cxt.canvas.height);
    for (var i = 0; i < balls.length; i++) {
        cxt.fillStyle = balls[i].color;
        cxt.beginPath();
        cxt.arc(balls[i].x, cxt.canvas.height - balls[i].y, balls[i].r, 0, 2 * Math.PI);
        cxt.closePath();
        cxt.fill();
    }
}
function touchBall(ball1, ball2) {
    let distance = Math.pow(Math.pow(ball1.x - ball2.x, 2) + Math.pow(ball1.y - ball2.y, 2), 0.5);
    if (distance <= ball1.r || distance <= ball2.r) {
        return "deep_touch";
    }
    else if (distance <= ball1.r + ball2.r) {
        return "shallow_touch";
    }
    else {
        return "no_touch";
    }
}
function collision(ball1, ball2) {
    //把ball1作为参考系,此参考系记为B,原参考系记为A。计算B下ball2的速度，坐标
    let relative_vx = ball1.vx;
    let relative_vy = ball1.vy;
    let relative_x = ball1.x;
    let relative_y = ball1.y;
    let vx = ball2.vx - relative_vx;
    let vy = ball2.vy - relative_vy;
    let x = ball2.x - relative_x;
    let y = ball2.y - relative_y;

    //以相对速度v0的方向 为x轴 作坐标旋转变换，变换后的参考系记为C
    let v0 = Math.pow(Math.pow(vx, 2) + Math.pow(vy, 2), 0.5);
    let sin_o = vy / v0;
    let cos_o = vx / v0;
    //作旋转变换
    let xuan_x = x * cos_o + y * sin_o;
    let xuan_y = -x * sin_o + y * cos_o;

    //计算旋转坐标系C下ball1的速度方向β,速度方向为ball1相对于ball2的方向
    let distance = Math.pow(Math.pow(xuan_x, 2) + Math.pow(xuan_y, 2), 0.5);
    let cos_B = -xuan_x / distance;
    let sin_B = -xuan_y / distance;
    //计算C下的ball1的速度和速度分量
    let ball1_v_C = (2 * ball2.m * v0 * cos_B) / (ball1.m + ball2.m);
    let ball1_vx_C = ball1_v_C * cos_B;
    let ball1_vy_C = ball1_v_C * sin_B;

    //计算C下的ball2的速度和速度分量
    let ball2_v_C_pingfang = v0 * v0 - (ball1.m * ball1_v_C * ball1_v_C) / ball2.m;
    let ball2_v_C;
    let ball2_vx_C;
    let ball2_vy_C;
    let sin_a;
    let cos_a;
    if (ball2_v_C_pingfang <= 0) {
        //若碰撞后ball2静止，应单独计算，防止出现 除0异常,负数开方异常
        let ball2_v_C = 0;
        ball2_vx_C = 0;
        ball2_vy_C = 0;
    }
    else {
        ball2_v_C = Math.pow((v0 * v0 - (ball1.m * ball1_v_C * ball1_v_C) / ball2.m), 0.5);
        sin_a = -(ball1.m * ball1_v_C * sin_B) / (ball2.m * ball2_v_C);
        cos_a = (ball2.m * v0 - ball1.m * ball1_v_C * cos_B) / (ball2.m * ball2_v_C);
        ball2_vx_C = ball2_v_C * cos_a;
        ball2_vy_C = ball2_v_C * sin_a;
    }

    //整理C下两球的速度。变换回B参考系
    let myArray_C = [[ball1_vx_C, ball1_vy_C], [ball2_vx_C, ball2_vy_C]];
    let myArray_B = new Array();
    for (let i = 0; i < myArray_C.length; i++) {
        myArray_B[i] = new Array();
        myArray_B[i][0] = myArray_C[i][0] * cos_o - myArray_C[i][1] * sin_o;
        myArray_B[i][1] = myArray_C[i][0] * sin_o + myArray_C[i][1] * cos_o;
    }

    ball1.vx = myArray_B[0][0] + relative_vx;
    ball1.vy = myArray_B[0][1] + relative_vy;
    ball2.vx = myArray_B[1][0] + relative_vx;
    ball2.vy = myArray_B[1][1] + relative_vy;
}
function collision_collapse(ball1, ball2) {
    let ball = {};
    ball.m = ball1.m + ball2.m;
    ball.vx = (ball1.m * ball1.vx + ball2.m * ball2.vx) / ball.m;
    ball.vy = (ball1.m * ball1.vy + ball2.m * ball2.vy) / ball.m;
    ball.x = (ball1.m * ball1.x + ball2.m * ball2.x) / ball.m;
    ball.y = (ball1.m * ball1.y + ball2.m * ball2.y) / ball.m;
    ball.r = Math.pow(ball1.r * ball1.r + ball2.r * ball2.r, 0.5);
    ball.color = (ball1.r > ball2.r) ? ball1.color : ball2.color;
    return ball;
}
function iftouchwall() {
    for (var i = 0; i < balls.length; i++) {
        if (balls[i].y >= cxt.canvas.height - balls[i].r) {
            balls[i].y = cxt.canvas.height - balls[i].r;
            balls[i].vy = -balls[i].vy;
        }
        if (balls[i].y <= balls[i].r) {
            balls[i].y = balls[i].r;
            balls[i].vy = -balls[i].vy;
        }
        if (balls[i].x >= cxt.canvas.width - balls[i].r) {
            balls[i].x = cxt.canvas.width - balls[i].r;
            balls[i].vx = -balls[i].vx;
        }
        if (balls[i].x <= balls[i].r) {
            balls[i].x = balls[i].r;
            balls[i].vx = -balls[i].vx;
        }
    }
}
function update() {
    for (let i = 0; i < balls.length; i++) {
        for (let j = i + 1; j < balls.length;) {
            if (touchBall(balls[i], balls[j]) === "shallow_touch") {
                collision(balls[i], balls[j]);
                j++;
            } else if (touchBall(balls[i], balls[j]) === "deep_touch") {
                balls[i] = collision_collapse(balls[i], balls[j]);
                balls.splice(j, 1);
            } else {
                j++;
            }
        }
    }
    iftouchwall();
    for (var i = 0; i < balls.length; i++) {
        balls[i].x += balls[i].vx;
        balls[i].y += balls[i].vy;
    }
}
// 运行区
window.onload = function () {
    initballs();
    intervalId = setInterval(function () {
        update();
        render(cxt);
    }, 4)
}